let ws;

export function getWebSocket() {
  if (!ws) {
    ws = new WebsocketClient();
  }
  return ws;
}

class WebsocketClient {
  constructor(props) {
    this.reconnectTimer = null; // 重连定时器
    this.reconnectTimeout = 5 * 1000; // 自动重连时间间隔
    this.lockReconnect = false;
  }

  open = (url, onopen) => {
    this.url = url;
    this.ws = new WebSocket(url);

    this.ws.onopen = (evt) => {
      heartCheck.start();
      onopen && onopen();
      this.onopen(evt);
    };

    this.ws.onmessage = (evt) => {
      heartCheck.start();
      this.onmessage(evt);
    };

    this.ws.onclose = (evt) => {
      switch (evt.code) {
        case 1000: // CLOSE_NORMAL
        case 4001: // 退出登录
          break;
        default:
          this.reconnect(); // 重连
          break;
      }
      this.onclose(evt);
    };

    this.ws.onerror = (evt) => {
      switch (evt.code) {
        case 'ECONNREFUSED':
          this.reconnect();
          break;
        default:
          this.onerror(evt);
          break;
      }
    };
  };

  // 重连
  reconnect = () => {
    if (this.lockReconnect) {
      return;
    }
    console.warn('websocket reconnect...');
    this.lockReconnect = true;
    if (this.reconnectTimer) {
      clearTimeout(this.reconnectTimer);
    }
    this.reconnectTimer = setTimeout(() => {
      this.lockReconnect = false;
      this.open(this.url);
    }, this.reconnectTimeout);
  };

  send = (data) => {
    try {
      if (this.ws.readyState === WebSocket.OPEN) {
        this.ws.send(JSON.stringify(data));
      } else {
        this.open(this.url, () => {
          if (this.ws.readyState === WebSocket.OPEN) {
            this.ws.send(JSON.stringify(data));
          }
        });
      }
    } catch (err) {
      console.log(err);
    }
  };

  close = (data) => {
    if (this.ws) {
      this.ws.close(data);
    }
  };

  onopen = (evt) => {};
  onmessage = (evt) => {};
  onclose = (evt) => {};
  onerror = (evt) => {};
}

// 心跳检测
const heartCheck = {
  clientTimeout: 5000, // 客户端5秒钟发送一次心跳
  serverTimeout: 7000, // 服务端7秒没响应则重连
  clientTimer: null, // 客户端定时器
  serverTimer: null, // 服务端定时器
  reset: () => {
    clearTimeout(this.clientTimer);
    clearTimeout(this.serverTimer);
    return this;
  },
  start: function () {
    if (this.clientTimer) {
      clearTimeout(this.clientTimer);
    }
    if (this.serverTimer) {
      clearTimeout(this.serverTimer);
    }
    this.clientTimer = setTimeout(() => {
      ws.send({ command: 'ping', msg: 'ping', type: 1 });
      this.serverTimer = setTimeout(() => {
        // 指定时间内没收到服务端响应，则主动关闭，从而触发重连
        ws.close();
      }, this.serverTimeout);
    }, this.clientTimeout);
  }
};

export default WebsocketClient;
